home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / hobby / ast44src.zip / XDEVICE.C < prev    next >
C/C++ Source or Header  |  1995-02-11  |  21KB  |  705 lines

  1. /*
  2. ** Astrolog (Version 4.40) File: xdevice.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. #include "astrolog.h"
  38.  
  39.  
  40. #ifdef GRAPH
  41. /*
  42. ******************************************************************************
  43. ** Bitmap File Routines.
  44. ******************************************************************************
  45. */
  46.  
  47. /* Write the bitmap array to a previously opened file in a format that   */
  48. /* can be read in by the Unix X commands bitmap and xsetroot. The 'mode' */
  49. /* parameter defines how much white space is put in the file.            */
  50.  
  51. void WriteXBitmap(file, name, mode)
  52. FILE *file;
  53. char *name, mode;
  54. {
  55.   int x, y, i, temp = 0;
  56.   _int value;
  57.  
  58.   fprintf(file, "#define %s_width %d\n" , name, gs.xWin);
  59.   fprintf(file, "#define %s_height %d\n", name, gs.yWin);
  60.   fprintf(file, "static %s %s_bits[] = {",
  61.     mode != 'V' ? "char" : "short", name);
  62.   for (y = 0; y < gs.yWin; y++) {
  63.     x = 0;
  64.     do {
  65.  
  66.       /* Process each row, eight columns at a time. */
  67.  
  68.       if (y + x > 0)
  69.         fprintf(file, ",");
  70.       if (temp == 0)
  71.         fprintf(file, "\n%s",
  72.           mode == 'N' ? "  " : (mode == 'C' ? " " : ""));
  73.       value = 0;
  74.       for (i = (mode != 'V' ? 7 : 15); i >= 0; i--)
  75.         value = (value << 1) + (!(FBmGet(gi.bm, x+i, y)^
  76.           (gs.fInverse*15))^gs.fInverse && (x + i < gs.xWin));
  77.       if (mode == 'N')
  78.         putc(' ', file);
  79.       fprintf(file, "0x");
  80.       if (mode == 'V')
  81.         fprintf(file, "%c%c",
  82.           ChHex(value >> 12), ChHex((value >> 8) & 15));
  83.       fprintf(file, "%c%c",
  84.         ChHex((value >> 4) & 15), ChHex(value & 15));
  85.       temp++;
  86.  
  87.       /* Is it time to skip to the next line while writing the file yet? */
  88.  
  89.       if ((mode == 'N' && temp >= 12) ||
  90.           (mode == 'C' && temp >= 15) ||
  91.           (mode == 'V' && temp >= 11))
  92.         temp = 0;
  93.       x += (mode != 'V' ? 8 : 16);
  94.     } while (x < gs.xWin);
  95.   }
  96.   fprintf(file, "};\n");
  97. }
  98.  
  99.  
  100. /* Write the bitmap array to a previously opened file in a simple boolean    */
  101. /* Ascii rectangle, one char per pixel, where '#' represents an off bit and  */
  102. /* '-' an on bit. The output format is identical to the format generated by  */
  103. /* the Unix bmtoa command, and it can be converted into a bitmap with atobm. */
  104.  
  105. void WriteAscii(file)
  106. FILE *file;
  107. {
  108.   int x, y, i;
  109.  
  110.   for (y = 0; y < gs.yWin; y++) {
  111.     for (x = 0; x < gs.xWin; x++) {
  112.       i = FBmGet(gi.bm, x, y);
  113.       if (gs.fColor)
  114.         putc(ChHex(i), file);
  115.       else
  116.         putc(i ? '-' : '#', file);
  117.     }
  118.     putc('\n', file);
  119.   }
  120. }
  121.  
  122.  
  123. /* Write the bitmap array to a previously opened file in the bitmap format  */
  124. /* used in Microsoft Windows for its .bmp extension files. This is a pretty */
  125. /* efficient format, only requiring a small header, and one bit per pixel   */
  126. /* for monochrome graphics, or four bits per pixel for full color.          */
  127.  
  128. void WriteBmp(file)
  129. FILE *file;
  130. {
  131.   int x, y;
  132.   dword value;
  133.  
  134.   /* Note that we sometimes only write a part of the full bitmap to disk   */
  135.   /* during the call, as done when the bitmap is being generated in bands. */
  136.  
  137.   if (gi.yBand == 0 || gi.yOffset + gi.yBand >= gs.yWin) {
  138.     /* BitmapFileHeader */
  139.     PutByte('B'); PutByte('M');
  140.     PutLong(14+40 + (gs.fColor ? 64 : 8) +
  141.       (long)4*gs.yWin*((gs.xWin-1 >> (gs.fColor ? 3 : 5))+1));
  142.     PutWord(0); PutWord(0);
  143.     PutLong(14+40 + (gs.fColor ? 64 : 8));
  144.     /* BitmapInfo / BitmapInfoHeader */
  145.     PutLong(40);
  146.     PutLong(gs.xWin); PutLong(gs.yWin);
  147.     PutWord(1); PutWord(gs.fColor ? 4 : 1);
  148.     PutLong(0 /*BI_RGB*/); PutLong(0);
  149.     PutLong(0); PutLong(0);
  150.     PutLong(0); PutLong(0);
  151.     /* RgbQuad */
  152.     if (gs.fColor)
  153.       for (x = 0; x < 16; x++) {
  154.         PutByte(RGBB(rgbbmp[x])); PutByte(RGBG(rgbbmp[x]));
  155.         PutByte(RGBR(rgbbmp[x])); PutByte(0);
  156.       }
  157.     else {
  158.       PutLong(0);
  159.       PutByte(255); PutByte(255); PutByte(255); PutByte(0);
  160.     }
  161.   }
  162.   /* Data */
  163.   for (y = (gi.yBand ? Min(gi.yBand, gs.yWin - gi.yOffset) : gs.yWin) - 1;
  164.     y >= 0; y--) {
  165.     value = 0;
  166.     for (x = 0; x < gs.xWin; x++) {
  167.       if ((x & (gs.fColor ? 7 : 31)) == 0 && x > 0) {
  168.         PutLong(value);
  169.         value = 0;
  170.       }
  171.       if (gs.fColor)
  172.         value |= (dword)FBmGet(gi.bm, x, y) << ((x & 7 ^ 1) << 2);
  173.       else
  174.         if (FBmGet(gi.bm, x, y))
  175.           value |= (dword)1 << (x & 31 ^ 7);
  176.     }
  177.     PutLong(value);
  178.   }
  179. }
  180.  
  181.  
  182. /* Begin the work of creating a graphics file. Prompt for a filename if */
  183. /* need be, and if valid, create the file and open it for writing.      */
  184.  
  185. void BeginFileX()
  186. {
  187.   char line[cchSzDef];
  188.  
  189.   if (gi.szFileOut == NULL && (
  190. #ifdef PS
  191. gi.fEps ||
  192. #endif
  193.     gs.fMeta || (gs.fBitmap && gs.chBmpMode == 'B'))) {
  194.     sprintf(line, "(It is recommended to specify an extension of '.%s'.)\n",
  195.       gs.fBitmap ? "bmp" :
  196. #ifdef PS
  197.       (gi.fEps ? "eps" : "wmf")
  198. #else
  199.       "wmf"
  200. #endif
  201.       );
  202.     PrintSzScreen(line);
  203.   }
  204.   loop {
  205.     if (gi.szFileOut == NULL) {
  206.       sprintf(line, "Enter name of file to write %s to",
  207.         gs.fBitmap ? "bitmap" : (gs.fPS ? "PostScript" : "metafile"));
  208.       InputString(line, line);
  209.       gi.szFileOut = line;
  210.     }
  211.     gi.file = fopen(gi.szFileOut, gs.fPS ? "w" : "wb");
  212.     if (gi.file != NULL)
  213.       break;
  214.     else {
  215.       PrintWarning("Couldn't create output file.");
  216.       gi.szFileOut = NULL;
  217.     }
  218.   }
  219. }
  220.  
  221.  
  222. /* Finish up the work of creating a graphics file. This basically consists */
  223. /* of just calling the appropriate routine to actually write the data in   */
  224. /* memory to a file for bitmaps and metafiles, although for PostScript we  */
  225. /* just close file as we were already writing while creating the chart.    */
  226.  
  227. void EndFileX()
  228. {
  229.   char sz[cchSzDef];
  230.  
  231.   if (gs.fBitmap) {
  232.     if (gi.yBand) {
  233.       sprintf(sz, "Writing part %d of chart bitmap to file.",
  234.         gi.yOffset / gi.yBand + 1);
  235.       PrintNotice(sz);
  236.     } else
  237.       PrintNotice("Writing chart bitmap to file.");
  238.     if (gs.chBmpMode == 'B')
  239.       WriteBmp(gi.file);
  240.     else if (gs.chBmpMode == 'A')
  241.       WriteAscii(gi.file);
  242.     else
  243.       WriteXBitmap(gi.file, gi.szFileOut, gs.chBmpMode);
  244.   }
  245. #ifdef PS
  246.   else if (gs.fPS)
  247.     PsEnd();
  248. #endif
  249. #ifdef META
  250.   else {
  251.     PrintNotice("Writing metafile to disk.");
  252.     WriteMeta(gi.file);
  253.   }
  254. #endif
  255.   if (!gs.fBitmap || gi.yOffset == 0) {
  256.     fclose(gi.file);
  257.     gi.yBand = 0;
  258.   }
  259. }
  260.  
  261.  
  262. #ifdef PS
  263. /*
  264. ******************************************************************************
  265. ** PostScript File Routines.
  266. ******************************************************************************
  267. */
  268.  
  269. /* Table of PostScript header alias lines used by the program. */
  270.  
  271. CONST char FAR szPsFunctions[] =
  272. "/languagelevel where{pop languagelevel}{1}ifelse\
  273.  2 lt{\n\
  274. /sf{exch findfont exch\
  275.  dup type/arraytype eq{makefont}{scalefont}ifelse setfont}bind def\n\
  276. /rf{gsave newpath\n\
  277. 4 -2 roll moveto\
  278.  dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath\n\
  279. fill grestore}bind def\n\
  280. /rc{newpath\n\
  281. 4 -2 roll moveto\
  282.  dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath\n\
  283. clip newpath}bind def\n\
  284. }{/sf/selectfont load def/rf/rectfill load def\
  285. /rc/rectclip load def}ifelse\n\
  286. /center{0 begin gsave dup 4 2 roll\
  287.  translate newpath 0 0 moveto\
  288.  false charpath flattenpath pathbbox\
  289.  /URy exch def/URx exch def/LLy exch def/LLx exch def\
  290.  URx LLx sub 0.5 mul LLx add neg URy LLy sub 0.5 mul LLy add neg\
  291.  0 0 moveto rmoveto\
  292.  show grestore end}bind def\n\
  293. /center load 0 4 dict put\n\
  294. /c{setrgbcolor}bind def\n\
  295. /d{moveto 0 0 rlineto}bind def\n\
  296. /l{4 2 roll moveto lineto}bind def\n\
  297. /t{lineto}bind def\n\
  298. /el{newpath matrix currentmatrix 5 1 roll translate scale\
  299.  0 0 1 0 360 arc setmatrix stroke}bind def\n";
  300.  
  301.  
  302. /* Write a command to flush the PostScript buffer. */
  303.  
  304. void PsStrokeForce()
  305. {
  306.   if (gi.cStroke > 0) {              /* render any existing path */
  307.     fprintf(gi.file, "stroke\n");
  308.     gi.cStroke = 0;
  309.     gi.xPen = -1;                    /* Invalidate PolyLine cache */
  310.   }
  311. }
  312.  
  313.  
  314. /* Indicate that a certain number of PostScript commands have been done. */
  315.  
  316. void PsStroke(n)
  317. int n;
  318. {
  319.   gi.cStroke += n;
  320.   if (gi.cStroke > 2000)    /* Whenever we reach a certain limit, flush. */
  321.     PsStrokeForce();
  322. }
  323.  
  324.  
  325. /* Set the type of line end to be used by PostScript commands. If linecap */
  326. /* is true, then the line ends are rounded, otherwise they are squared.   */
  327.  
  328. void PsLineCap(fLineCap)
  329. bool fLineCap;
  330. {
  331.   if (fLineCap != gi.fLineCap) {
  332.     PsStrokeForce();
  333.     fprintf(gi.file, "%d setlinecap\n", fLineCap);
  334.     gi.fLineCap = fLineCap;
  335.   }
  336. }
  337.  
  338.  
  339. /* Set the dash length to be used by PostScript line commands. */
  340.  
  341. void PsDash(dashoff)
  342. int dashoff;
  343. {
  344.   if (dashoff != gi.nDash) {
  345.     PsStrokeForce();
  346.     if (dashoff)
  347.       fprintf(gi.file, "[%d %d", PSMUL, dashoff * PSMUL);
  348.     else
  349.       fprintf(gi.file, "[");
  350.     fprintf(gi.file, "]0 setdash\n");
  351.     gi.nDash = dashoff;
  352.   }
  353. }
  354.  
  355.  
  356. /* Set a linewidth size to be used by PostScript figure primitive commands. */
  357.  
  358. void PsLineWidth(linewidth)
  359. int linewidth;
  360. {
  361.   if ((real)linewidth != gi.rLineWid) {
  362.     PsStrokeForce();
  363.     fprintf(gi.file, "%d setlinewidth\n", linewidth);
  364.     gi.rLineWid = (real)linewidth;
  365.   }
  366. }
  367.  
  368.  
  369. /* Set a system font and size to be used by PostScript text commands. */
  370.  
  371. void PsFont(psfont)
  372. int psfont;
  373. {
  374.   int z;
  375.  
  376.   if (psfont != gi.nFont && gs.fFont) {
  377.     if (psfont <= 2) {
  378.       z = psfont == 1 ? 32*PSMUL : 23*PSMUL;
  379.       fprintf(gi.file, "/Astro[%d 0 0 -%d 0 0]sf\n", z, z);
  380.     } else if (psfont == 3) {
  381.       z = 26*PSMUL;
  382.       fprintf(gi.file, "/Times-Roman[%d 0 0 -%d 0 0]sf\n", z, z);
  383.     } else {
  384.       z = 10*PSMUL;
  385.       fprintf(gi.file, "/Courier[%d 0 0 -%d 0 0]sf\n", z, z);
  386.     }
  387.     gi.nFont = psfont;
  388.   }
  389. }
  390.  
  391.  
  392. /* Prompt the user for the name of a file to write the PostScript file to */
  393. /* (if not already specified), open it, and write out file header info.   */
  394.  
  395. void PsBegin()
  396. {
  397.   fprintf(gi.file, "%%!PS-Adobe-2.0");
  398.   if (gi.fEps)
  399.     fprintf(gi.file, " EPSF-2.0");
  400.   fprintf(gi.file, "\n%%%%Title: %s\n", gi.szFileOut);
  401.   fprintf(gi.file, "%%%%Creator: %s %s\n", szAppName, szVersionCore);
  402.   fprintf(gi.file, "%%%%CreationDate: %s\n", szDateCore);
  403.   if (gi.fEps) {
  404.     fprintf(gi.file, "%%%%BoundingBox: 0 0 %d %d\n", gs.xWin, gs.yWin);
  405.     fprintf(gi.file, "%%%%EndComments\n");
  406.     fprintf(gi.file, "%%%%BeginSetup\n");
  407.     fprintf(gi.file, szPsFunctions, 6 * PSMUL, 6 * PSMUL);
  408.     fprintf(gi.file, "%%%%EndSetup\n");
  409.     fprintf(gi.file, "0 0 %d %d rc\n", gs.xWin, gs.yWin);
  410.   } else {
  411.     fprintf(gi.file, "%%%%Pages: 1 1\n");
  412.     fprintf(gi.file, "%%%%DocumentFonts: (atend)\n");
  413.     fprintf(gi.file, "%%%%BoundingBox: %d %d %d %d\n", PSGUTTER, PSGUTTER,
  414.       (int)(gs.xInch*72.0+rRound)-PSGUTTER,
  415.       (int)(gs.yInch*72.0+rRound)-PSGUTTER);
  416.     fprintf(gi.file, "%%%%EndComments\n");
  417.     fprintf(gi.file, "%%%%BeginProcSet: common\n");
  418.     fprintf(gi.file, szPsFunctions, 6 * PSMUL, 6 * PSMUL);
  419.     fprintf(gi.file, "%%%%EndProcSet\n");
  420.     fprintf(gi.file, "%%%%Page: 1 1\n");
  421.   }
  422.   PsFont(2);
  423.   fprintf(gi.file, "gsave\n");
  424.   PsLineWidth(gi.nPenWid/2);
  425.   gi.xPen = -1;
  426.   PrintNotice("Creating PostScript chart file.");
  427. }
  428.  
  429.  
  430. /* Write out trailing information to the PostScript file and close it. */
  431.  
  432. void PsEnd()
  433. {
  434.   PsStrokeForce();
  435.   if (gi.fEps)
  436.     fprintf(gi.file, "%%%%EOF\n");
  437.   else {
  438.     fprintf(gi.file, "showpage\n");
  439.     fprintf(gi.file, "%%%%PageTrailer\n");
  440.     fprintf(gi.file, "%%%%Trailer\n");
  441.     fprintf(gi.file, "%%%%DocumentFonts: Times-Roman\n");
  442.     if (gs.fFont) {
  443.       fprintf(gi.file, "%%%%+ Courier\n");
  444.       fprintf(gi.file, "%%%%+ Astro\n");
  445.     }
  446.   }
  447.   fclose(gi.file);
  448. }
  449. #endif /* PS */
  450.  
  451.  
  452. #ifdef META
  453. /*
  454. ******************************************************************************
  455. ** Metafile Routines.
  456. ******************************************************************************
  457. */
  458.  
  459. /* Output one 16 bit or 32 bit value into the metafile buffer stream. */
  460.  
  461. void MetaWord(w)
  462. word w;
  463. {
  464.   char sz[cchSzDef];
  465.  
  466.   if ((hpbyte)gi.pwMetaCur - gi.bm >= gi.cbMeta) {
  467.     sprintf(sz, "Metafile would be more than %ld bytes.", gi.cbMeta);
  468.     PrintError(sz);
  469.     Terminate(tcFatal);
  470.   }
  471.   *gi.pwMetaCur = w;
  472.   gi.pwMetaCur++;
  473. }
  474.  
  475. void MetaLong(l)
  476. long l;
  477. {
  478.   MetaWord(WLo(l));
  479.   MetaWord(WHi(l));
  480. }
  481.  
  482.  
  483. /* Output any necessary metafile records to make the current actual     */
  484. /* settings of line color, fill color, etc, be those that we know are   */
  485. /* desired. This is generally called by the primitives routines before  */
  486. /* any figure record is actually written into a metafile. We wait until */
  487. /* the last moment before changing any settings to ensure that we don't */
  488. /* output any unnecessary records, e.g. two select colors in a row.     */
  489.  
  490. void MetaSelect()
  491. {
  492.   if (gi.kiLineDes != gi.kiLineAct) {
  493.     MetaSelectObject(gi.kiLineDes);
  494.     gi.kiLineAct = gi.kiLineDes;
  495.   }
  496.   if (gi.kiFillDes != gi.kiFillAct) {
  497.     MetaSelectObject(16*4 + gi.kiFillDes);
  498.     gi.kiFillAct = gi.kiFillDes;
  499.   }
  500.   if (gi.nFontDes != gi.nFontAct) {
  501.     MetaSelectObject(16*5 + gi.nFontDes);
  502.     gi.nFontAct = gi.nFontDes;
  503.   }
  504.   if (gi.kiTextDes != gi.kiTextAct) {
  505.     MetaTextColor(rgbbmp[gi.kiTextDes]);
  506.     gi.kiTextAct = gi.kiTextDes;
  507.   }
  508.   if (gi.nAlignDes != gi.nAlignAct) {
  509.     MetaTextAlign(gi.nAlignDes);
  510.     gi.nAlignAct = gi.nAlignDes;
  511.   }
  512.   gi.xPen = -1;    /* Invalidate PolyLine cache */
  513. }
  514.  
  515.  
  516. /* Output initial metafile header information into our metafile buffer. */
  517. /* We also setup and create all pen, brush, and font objects that may   */
  518. /* possibly be used in the generation and playing of the picture.       */
  519.  
  520. void MetaInit()
  521. {
  522.   int i, j, k;
  523.  
  524.   gi.pwMetaCur = (word HFAR *)gi.bm;
  525.   /* Placable Metaheader */
  526.   MetaLong(0x9AC6CDD7L);
  527.   MetaWord(0);      /* Not used */
  528.   MetaWord(0); MetaWord(0);
  529.   MetaWord(gs.xWin); MetaWord(gs.yWin);
  530.   MetaWord(gs.xWin/6);                     /* Units per inch */
  531.   MetaLong(0L);     /* Not used */
  532.   MetaWord(0x9AC6 ^ 0xCDD7 ^ gs.xWin ^ gs.yWin ^ gs.xWin/6);  /* Checksum */
  533.   /* Metaheader */
  534.   MetaWord(1);                      /* Metafile type                    */
  535.   MetaWord(9);                      /* Size of header in words          */
  536.   MetaWord(0x300);                  /* Windows version                  */
  537.   MetaLong(0L);                     /* Size of entire metafile in words */
  538.   MetaWord(16*5+1+(gs.fFont>0)*4);  /* Number of objects in metafile    */
  539.   MetaLong(17L);                    /* Size of largest record in words  */
  540.   MetaWord(0);                      /* Not used                         */
  541.   /* Setup */
  542.   MetaEscape(17);
  543.   MetaLong(LFromBB('A', 's', 't', 'r'));  /* "Astr" */
  544.   MetaWord(4);                            /* Creator */
  545.   MetaLong(14L);                          /* Bytes in string */
  546.   MetaLong(LFromBB('A', 's', 't', 'r'));  /* "Astr" */
  547.   MetaLong(LFromBB('o', 'l', 'o', 'g'));  /* "olog" */
  548.   MetaLong(LFromBB(' ', '4', '.', '4'));  /* " 4.4" */
  549.   MetaWord(WFromBB('0', 0));              /* "0"    */
  550.   MetaSaveDc();
  551.   MetaWindowOrg(0, 0);
  552.   MetaWindowExt(gs.xWin, gs.yWin);
  553.   MetaBkMode(1 /* Transparent */);
  554.   /* Colors */
  555.   for (j = 1; j <= 4; j++)
  556.     for (i = 0; i < 16; i++) {
  557.       k = j <= 1 ? gi.nPenWid : 0;
  558.       MetaCreatePen(j <= 2 ? 0 : j-2 /* PS_SOLID; PS_DASH; PS_DOT */,
  559.         k, rgbbmp[i]);
  560.     }
  561.   for (i = 0; i < 16; i++) {
  562.     MetaCreateBrush(0 /* BS_SOLID */, rgbbmp[i]);
  563.   }
  564.   MetaCreateBrush(1 /* BS_NULL */, 0L);
  565.   /* Fonts */
  566.   if (gs.fFont) {
  567.     MetaCreateFont(5, 0, -8*gi.nScale, 2 /* Symbol Charset */);
  568.     MetaWord(WFromBB(1 /* Draft */, 1 | 0x10 /* Fixed | Roman */));
  569.     MetaLong(LFromBB('W', 'i', 'n', 'g'));
  570.     MetaLong(LFromBB('d', 'i', 'n', 'g'));
  571.     MetaWord(WFromBB('s', 0));
  572.  
  573.     MetaCreateFont(8, 0, -6*gi.nScale, 0 /* Ansi Charset */);
  574.     MetaWord(WFromBB(0 /* Default */, 2 | 0x10 /* Variable | Roman */));
  575.     MetaLong(LFromBB('T', 'i', 'm', 'e'));
  576.     MetaLong(LFromBB('s', ' ', 'N', 'e'));
  577.     MetaLong(LFromBB('w', ' ', 'R', 'o'));
  578.     MetaLong(LFromBB('m', 'a', 'n', 0));
  579.  
  580.     MetaCreateFont(6, 6*METAMUL, 10*METAMUL, 0 /* Ansi Charset */);
  581.     MetaWord(WFromBB(1 /* Draft */, 1 | 0x30 /* Fixed | Modern */));
  582.     MetaLong(LFromBB('C', 'o', 'u', 'r'));
  583.     MetaLong(LFromBB('i', 'e', 'r', ' '));
  584.     MetaLong(LFromBB('N', 'e', 'w', 0));
  585.  
  586.     MetaCreateFont(8, 0, -11*gi.nScale, 0 /* Ansi Charset */);
  587.     MetaWord(WFromBB(0 /* Default */, 2 | 0 /* Variable | Don't Care */));
  588.     MetaLong(LFromBB('A', 's', 't', 'r'));
  589.     MetaLong(LFromBB('o', '-', 'S', 'e'));
  590.     MetaLong(LFromBB('m', 'i', 'B', 'o'));
  591.     MetaLong(LFromBB('l', 'd', 0, 0));
  592.   }
  593. }
  594.  
  595.  
  596. /* Output trailing records to indicate the end of the metafile and then */
  597. /* actually write out the entire buffer to the specifed file.           */
  598.  
  599. void WriteMeta(file)
  600. FILE *file;
  601. {
  602.   word HFAR *w;
  603. #if FALSE
  604.   int i;
  605.  
  606.   for (i = 16*5+1+(gs.fFont>0)*4; i >= 0; i--) {
  607.     MetaDeleteObject(i);
  608.   }
  609. #endif
  610.   MetaRestoreDc();
  611.   MetaRecord(3, 0);    /* End record */
  612.   *(long HFAR *)(gi.bm + 22 + 6) =
  613.     ((long)((hpbyte)gi.pwMetaCur - gi.bm) - 22) / 2;
  614.   for (w = (word HFAR *)gi.bm; w < gi.pwMetaCur; w++) {
  615.     PutWord(*w);
  616.   }
  617. }
  618. #endif /* META */
  619.  
  620.  
  621. #ifdef MOUSE
  622. #ifdef PC
  623. /*
  624. ******************************************************************************
  625. ** Mouse Routines.
  626. ******************************************************************************
  627. */
  628.  
  629. static union REGS dosreg;
  630.  
  631.  
  632. /* Setup and initialize the PC graphics mouse, returning the number of    */
  633. /* buttons available, or zero for no mouse at all. Passed in is the pixel */
  634. /* size of the screen the mouse pointer is to be contained within.        */
  635.  
  636. int MouseInit(x, y)
  637. int x, y;
  638. {
  639.   int dx, cBtn;
  640.  
  641.   if (!gs.fMouse)
  642.     return 0;
  643.   dosreg.x.ax = 0;
  644.   int86(0x33, &dosreg, &dosreg);
  645.   if (!(gs.fMouse = dosreg.x.ax))
  646.     return 0;
  647.   cBtn = dosreg.x.bx;
  648.   dx = x - 1;
  649.   dosreg.x.ax = 7;
  650.   dosreg.x.cx = 0;
  651.   dosreg.x.dx = dx;
  652.   int86(0x33, &dosreg, &dosreg);
  653.   dx = y - 1;
  654.   dosreg.x.ax = 8;
  655.   dosreg.x.cx = 0;
  656.   dosreg.x.dx = dx;
  657.   int86(0x33, &dosreg, &dosreg);
  658.   return cBtn;
  659. }
  660.  
  661.  
  662. /* Turn on or hide the PC graphics mouse pointer. */
  663.  
  664. void MouseShow(fShow)
  665. bool fShow;
  666. {
  667.   int ax;
  668.  
  669.   if (!gs.fMouse)
  670.     return;
  671.   ax = fShow ? 1 : 2;
  672.   dosreg.x.ax = ax;
  673.   int86(0x33, &dosreg, &dosreg);
  674. }
  675.  
  676.  
  677. /* Fill out the current status of the mouse: its horizontal and vertical  */
  678. /* position, and button press status. We return false if the mouse hasn't */
  679. /* changed any from the last call (assuming that the previous values are  */
  680. /* stored in the input parameters) or if the mouse isn't active at all.   */
  681.  
  682. bool MouseStatus(x, y, btn)
  683. int *x, *y, *btn;
  684. {
  685.   int bx, cx, dx, fChange;
  686.  
  687.   if (!gs.fMouse)
  688.     return fFalse;
  689.   dosreg.x.ax = 3;
  690.   int86(0x33, &dosreg, &dosreg);
  691.   bx = dosreg.x.bx;
  692.   cx = dosreg.x.cx;
  693.   dx = dosreg.x.dx;
  694.   fChange = (cx != *x || dx != *y || bx != *btn);
  695.   *x = cx;
  696.   *y = dx;
  697.   *btn = bx;
  698.   return fChange;
  699. }
  700. #endif /* PC */
  701. #endif /* MOUSE */
  702. #endif /* GRAPH */
  703.  
  704. /* xdevice.c */
  705.